package cn.chinaunicom.smart.community.generator.helper;

import cn.chinaunicom.smart.community.generator.constant.GenConstant;
import cn.chinaunicom.smart.community.generator.entity.Column;
import cn.chinaunicom.smart.community.generator.entity.GeneratorConfig;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * 代码生成器工具类
 *
 * @author MrBird
 */
@Slf4j
@Component
public class GeneratorHelper {

    private Map<String, Function<Column, String>> functionMap = new HashMap<>(14);

    public GeneratorHelper() {
        init();
    }

    private void init() {
        // mysql 数据类型 对应 mybatis 的jdbcType类型
        // 日期型
        functionMap.put("date", x -> {
            x.setType("DATE");
            return x.getType();
        });
        functionMap.put("datetime", x -> {
            x.setType("TIMESTAMP");
            return x.getType();
        });
        functionMap.put("timestamp", x -> {
            x.setType("TIMESTAMP");
            return x.getType();
        });

        // 整型
        functionMap.put("bigint", x -> {
            x.setType("BIGINT");
            return x.getType();
        });
        functionMap.put("int", x -> {
            x.setType("INTEGER");
            return x.getType();
        });
        functionMap.put("integer", x -> {
            x.setType("INTEGER");
            return x.getType();
        });
        functionMap.put("tinyint", x -> {
            x.setType("INTEGER");
            return x.getType();
        });
        functionMap.put("smallint", x -> {
            x.setType("INTEGER");
            return x.getType();
        });

        // 浮点型
        functionMap.put("double", x -> {
            x.setType("DOUBLE");
            return x.getType();
        });
        functionMap.put("decimal", x -> {
            x.setType("DECIMAL");
            return x.getType();
        });
        functionMap.put("number", x -> {
            x.setType("NUMERIC");
            return x.getType();
        });
        functionMap.put("float", x -> {
            x.setType("FLOAT");
            return x.getType();
        });

        // 字符型
        functionMap.put("longtext", x -> {
            x.setType("LONGVARCHAR");
            return x.getType();
        });
        functionMap.put("char", x -> {
            x.setType("VARCHAR");
            return x.getType();
        });
        functionMap.put("text", x -> {
            x.setType("VARCHAR");
            return x.getType();
        });
        functionMap.put("varchar", x -> {
            x.setType("VARCHAR");
            return x.getType();
        });
        // 布尔型
        functionMap.put("bit", x -> {
            x.setType("BOOLEAN");
            return x.getType();
        });
    }


    public void generateEntityFile(List<Column> columns, GeneratorConfig configure) throws Exception {
        String suffix = GenConstant.JAVA_FILE_SUFFIX;
        String path = getFilePath(configure, configure.getEntityPackage(), suffix, false);
        String templateName = GenConstant.ENTITY_TEMPLATE;
        File entityFile = new File(path);
        JSONObject data = toJSONObject(configure);
        data.put("hasDate", false);
        data.put("hasBigDecimal", false);
        columns.forEach(c -> {
//            c.setField(SysUtils.underscoreToCamel(StringUtils.lowerCase(c.getName())));
            if (StringUtils.containsAny(c.getType(), "date", "datetime", "timestamp")) {
                data.put("hasDate", true);
            }
            if (StringUtils.containsAny(c.getType(), "decimal", "numeric")) {
                data.put("hasBigDecimal", true);
            }
        });
        data.put("columns", columns);
        this.generateFileByTemplate(templateName, entityFile, data);
    }

    public void generateMapperFile(List<Column> columns, GeneratorConfig configure) throws Exception {
        String suffix = GenConstant.MAPPER_FILE_SUFFIX;
        String path = getFilePath(configure, configure.getMapperPackage(), suffix, false);
        String templateName = GenConstant.MAPPER_TEMPLATE;
        File mapperFile = new File(path);
        generateFileByTemplate(templateName, mapperFile, toJSONObject(configure));
    }

    public void generateServiceFile(List<Column> columns, GeneratorConfig configure) throws Exception {
        String suffix = GenConstant.SERVICE_FILE_SUFFIX;
        String path = getFilePath(configure, configure.getServicePackage(), suffix, true);
        String templateName = GenConstant.SERVICE_TEMPLATE;
        File serviceFile = new File(path);
        generateFileByTemplate(templateName, serviceFile, toJSONObject(configure));
    }

    public void generateServiceImplFile(List<Column> columns, GeneratorConfig configure) throws Exception {
        String suffix = GenConstant.SERVICEIMPL_FILE_SUFFIX;
        String path = getFilePath(configure, configure.getServiceImplPackage(), suffix, false);
        String templateName = GenConstant.SERVICEIMPL_TEMPLATE;
        File serviceImplFile = new File(path);
        generateFileByTemplate(templateName, serviceImplFile, toJSONObject(configure));
    }

    public void generateControllerFile(List<Column> columns, GeneratorConfig configure) throws Exception {
        String suffix = GenConstant.CONTROLLER_FILE_SUFFIX;
        String path = getFilePath(configure, configure.getControllerPackage(), suffix, false);
        String templateName = GenConstant.CONTROLLER_TEMPLATE;
        File controllerFile = new File(path);
        generateFileByTemplate(templateName, controllerFile, toJSONObject(configure));
    }

    public void generateMapperXmlFile(List<Column> columns, GeneratorConfig configure) throws Exception {
//        String suffix = GenConstant.MAPPERXML_FILE_SUFFIX;
//        String path = getFilePath(configure, configure.getMapperXmlPackage(), suffix, false);
//        String templateName = GenConstant.MAPPERXML_TEMPLATE;
//        File mapperXmlFile = new File(path);
//        columns.forEach(c -> {
//                    genMapperJdbcType(c);
//                    c.setField(SysUtils.underscoreToCamel(StringUtils.lowerCase(c.getName())));
//                });
//        JSONObject data = toJSONObject(configure);
//        data.put("columns", columns);
//        generateFileByTemplate(templateName, mapperXmlFile, data);
    }

    /**
     * 生成jdbc类型
     *
     * @param column
     */
    private void genMapperJdbcType(Column column) {
        String type = functionMap.get(column.getType().toLowerCase()).apply(column);
        log.info("数据库表得列类型: {}", type);
    }


    @SuppressWarnings("all")
    private void generateFileByTemplate(String templateName, File file, Object data) throws Exception {
//        Template template = getTemplate(templateName);
//        Files.createParentDirs(file);
//        FileOutputStream fileOutputStream = new FileOutputStream(file);
//        try (Writer out = new BufferedWriter(new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8), 10240)) {
//            template.process(data, out);
//        } catch (Exception e) {
//            String message = "代码生成异常";
//            log.error(message, e);
//            throw new Exception(message);
//        }
    }

    private static String getFilePath(GeneratorConfig configure, String packagePath, String suffix, boolean serviceInterface) {
        String filePath = GenConstant.TEMP_PATH + configure.getJavaPath() +
                packageConvertPath(configure.getBasePackage() + "." + packagePath);
        if (serviceInterface) {
            filePath += "I";
        }
        filePath += configure.getClassName() + suffix;
        return filePath;
    }

    private static String packageConvertPath(String packageName) {
        return String.format("/%s/", packageName.contains(".") ? packageName.replaceAll("\\.", "/") : packageName);
    }

    private JSONObject toJSONObject(Object o) {
        return JSONObject.parseObject(JSONObject.toJSON(o).toString());
    }

//    private Template getTemplate(String templateName) throws Exception {
//        Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
//        String templatePath = GeneratorHelper.class.getResource("/templates/").getPath();
//        File file = new File(templatePath);
//        if (!file.exists()) {
//            templatePath = System.getProperties().getProperty(GenConstant.JAVA_TEMP_DIR);
//            file = new File(templatePath + File.separator + templateName);
//            FileUtils.copyInputStreamToFile(Objects.requireNonNull(ClassUtils.getDefaultClassLoader().getResourceAsStream("classpath:generator/templates/" + templateName)), file);
//        }
//        configuration.setDirectoryForTemplateLoading(new File(templatePath));
//        configuration.setDefaultEncoding(GenConstant.CHARSET_UTF8);
//        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
//        return configuration.getTemplate(templateName);
//    }
}
